package com.czmh.etc.onlinepubsys.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.czmh.etc.onlinepubsys.json.JsonResult;
import com.czmh.etc.onlinepubsys.json.mingchuang.JSONResult;
import com.czmh.etc.onlinepubsys.utils.RedisUtil;
import com.czmh.etc.onlinepubsys.wx.services.IWeixinOAuthService;
import io.swagger.annotations.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.weixin4j.Configuration;
import org.weixin4j.Weixin;
import org.weixin4j.WeixinBuilder;
import org.weixin4j.WeixinException;
import org.springframework.web.bind.annotation.*;
import org.weixin4j.*;
import org.weixin4j.component.JsSdkComponent;
import org.weixin4j.component.SnsComponent;
import org.weixin4j.http.HttpsClient;
import org.weixin4j.http.Response;
import org.weixin4j.loader.ITicketLoader;
import org.weixin4j.loader.ITokenLoader;
import org.weixin4j.model.js.WxConfig;
import org.weixin4j.model.sns.SnsAccessToken;
import org.weixin4j.model.sns.SnsUser;
import org.weixin4j.spring.web.WeixinJieruController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @ClassName 权限验证controller
 * @Description 用于c端用户注册和登陆
 * @Author Eric
 * @Date 2019/3/9 11:15
 * @Version 1.0v
 */
@CrossOrigin
@Api(tags = "用户授权管理中心")
@RestController
@RequestMapping("/wx/auth")
public class AuthController extends WeixinJieruController {

    private Logger logger = LoggerFactory.getLogger(AuthController.class);

    @Autowired
    IWeixinOAuthService weixinOAuthService;

    @Autowired
    ITicketLoader wxTicketLoader;

    @Autowired
    ITokenLoader wxTokenLoader;

    @Autowired
    RedisUtil redisUtil;

    /**
     * 微信授权第一步:
     * 微信服务器验证TOKEN
     *
     * @param request  HttpServletRequest
     * @param response HttpServletResponse
     * @throws IOException
     */
    @ApiOperation(value = "微信接入接口", notes = "微信接入接口")
    @GetMapping("/accessToken")
    public void accessToken(HttpServletRequest request, HttpServletResponse response) throws IOException {
        logger.info("微信接入接口=====================start====================");
        super.get(request, response);
        logger.info("接入结束==================end====================");
    }

    /**
     * 根据openid和token获取新token信息
     *
     * @param openId openId
     * @param token  token
     * @return
     */
    @ApiOperation(value = "获取token", notes = "防止用户token过期")
    @GetMapping("/getToken")
    public Map<String, String> getToken(@ApiParam(value = "用户id", required = false) @RequestParam(value = "openid", required = false) String openId,
                                        @ApiParam(value = "旧token值", required = false) @RequestParam(value = "token", required = false) String token) {
        logger.info("openId:{}", openId);
        logger.info("token:{}", token);
        Map userTokenVO = new HashMap();
        userTokenVO.put("token", token);
        userTokenVO.put("openId", openId);
        return userTokenVO;
    }

    /**
     * 微信授权第二步：
     * 1、用户同意授权，获取code
     * 2、通过code换取网页授权access_token
     *
     * @param request
     * @param response
     * @return
     * @throws IOException
     */
    @ApiOperation(value = "网页授权", notes = "网页授权")
    @GetMapping("/validateOAuth")
    public Boolean validateOAuth(HttpServletRequest request, HttpServletResponse response) throws IOException {
        logger.info("网页授权--------------------");
        //从session获取openid值
        String openid = (String) request.getSession().getAttribute("openid");
        logger.info("session中openid值：{}", openid);
        if (openid == null) {

            //TODO 从缓存组件获取openid或则token判断是否存在、存在并判断token是否过期
//        if (redisService.exists(openid)) {
//
//        }
            //获取code，换取openid
            String code = request.getParameter("code");
            logger.info("获取code，换取openid：code:{}", code);
            //如果没有获取到，则说明是直接访问页面链接，进行匿名获取
            if (code == null || code.equals("")) {
                //TODO 1 通过用户授权，获取code
                String returnUrl = Configuration.getProperty("weixin4j.oauth.url");
                logger.info("returnUrl:{}", returnUrl);
                logger.info("oauthId:{}", Configuration.getOAuthAppId());
//                OAuth2 oauth2 = new OAuth2();
                //将参数带入　　　　
                String url = weixinOAuthService.getOAuth2CodeBySnsapiBase(Configuration.getOAuthAppId(), returnUrl);
                logger.info("url:{}", url);
                response.sendRedirect(url);
                return false;
            } else {
                //TODO 2、通过code获取到token信息，然后做相对应的业务处理
                //查询用户的openid,因为code只能使用一次，所以将openid保存在页面中
                try {
                    SnsAccessToken snsAccessToken = weixinOAuthService.getOauthToken(Configuration.getOAuthAppId(), Configuration.getOAuthSecret(), code);
                    logger.info("authTokenVO--------------------authTokenVO:{}", snsAccessToken.toString());
                    logger.info("授权之后的openid===============2========openid:{}", snsAccessToken.getOpenid());
                    //获取授权得到的openid
                    openid = snsAccessToken.getOpenid();
                    request.getSession().setAttribute("openid", openid);
                    logger.info("授权之后的openid=======================openid:{}", openid);
                    //TODO 缓存到Redis或者其他缓存组件
                    //    redisService.set(openid, authTokenVO.getAccessToken(), authTokenVO.getExpiresIn());
                    //重定向到URL
                    logger.info("授权之后的accessToekn=======================accessToekn:{}", snsAccessToken.getAccess_token());


//                    //TODO 跳转到业务页面
                    String getTokenUrl = org.apache.commons.lang3.StringUtils.join(Configuration.getProperty("weixin4j.oauth.getToken"), "?openid=", openid, "&token=", snsAccessToken.getAccess_token());
                    logger.info("授权之后的getTokenUrl=======================openid:{}", getTokenUrl);
                    response.sendRedirect(getTokenUrl);
                    return true;
                } catch (WeixinException ex) {
                    //数据异常继续请求
                    logger.info("WeixinException异常处理{}", ex.getStackTrace());
//                    OAuth2 oauth2 = new OAuth2();
                    //将参数带入　　　　　　　　
                    String url = weixinOAuthService.getOAuth2CodeBySnsapiBase(Configuration.getOAuthAppId(), Configuration.getProperty("weixin4j.oauth.url"));
                    response.sendRedirect(url);
                    return false;
                }
            }
        }
        return true;
    }


    /**
     * 微信授权第二步：
     * 1、用户同意授权，获取code
     * 2、通过code换取网页授权access_token
     *
     * @param callBackUrl
     * @param request
     * @param response
     * @return
     * @throws IOException
     */
    @ApiOperation(value = "网页授权", notes = "网页授权")
    @GetMapping("/getOpenId")
    public Boolean getOpenId(@RequestParam(value = "callBackUrl", required = false) String callBackUrl, HttpServletRequest request, HttpServletResponse response) throws IOException {
        logger.info("网页授权--------------------");
        logger.info("==================callBackUrl：{}" + callBackUrl);
        //从session获取openid值
        String openid = (String) request.getSession().getAttribute("openid");
        logger.info("session中openid值：{}", openid);
        if (openid == null) {

            //TODO 从缓存组件获取openid或则token判断是否存在、存在并判断token是否过期
//        if (redisService.exists(openid)) {
//
//        }
            //获取code，换取openid
            String code = request.getParameter("code");
            logger.info("获取code，换取openid：code:{}", code);
            //如果没有获取到，则说明是直接访问页面链接，进行匿名获取
            if (code == null || "".equals(code)) {
                //TODO 1 通过用户授权，获取code
                String returnUrl = org.apache.commons.lang3.StringUtils.join(Configuration.getProperty("weixin4j.getOpenId.url"), "?callBackUrl=", callBackUrl);
                logger.info("==================授权地址：{}" + returnUrl);
                //将参数带入　　　　
                String url = weixinOAuthService.getOAuth2CodeBySnsapiBase(Configuration.getOAuthAppId(), returnUrl);
                logger.info("url:{}", url);
                response.sendRedirect(url);
                return false;
            } else {
                //TODO 2、通过code获取到token信息，然后做相对应的业务处理
                //查询用户的openid,因为code只能使用一次，所以将openid保存在页面中
                try {
                    SnsAccessToken snsAccessToken = weixinOAuthService.getOauthToken(Configuration.getOAuthAppId(), Configuration.getOAuthSecret(), code);
                    logger.info("authTokenVO--------------------authTokenVO:{}", snsAccessToken.toString());
                    logger.info("授权之后的openid===============2========openid:{}", snsAccessToken.getOpenid());
                    //获取授权得到的openid
                    openid = snsAccessToken.getOpenid();
                    request.getSession().setAttribute("openid", openid);
                    logger.info("授权之后的openid=======================openid:{}", openid);
                    //TODO 缓存到Redis或者其他缓存组件
                    //    redisService.set(openid, authTokenVO.getAccessToken(), authTokenVO.getExpiresIn());
                    //重定向到URL
                    logger.info("授权之后的accessToken=======================accessToken:{}", snsAccessToken.getAccess_token());
                    logger.info("授权之后的callBackUrl=======================callBackUrl:{}", callBackUrl);

//                    //TODO 跳转到业务页面
                    String getTokenUrl = org.apache.commons.lang3.StringUtils.join(callBackUrl, "&openid=", openid, "&token=", snsAccessToken.getAccess_token());
                    logger.info("授权之后的getTokenUrl=======================openid:{}", getTokenUrl);
                    response.sendRedirect(getTokenUrl);
                    return true;
                } catch (WeixinException ex) {
                    //数据异常继续请求
                    logger.info("WeixinException异常处理{}", ex.getStackTrace());
//                    OAuth2 oauth2 = new OAuth2();
                    //将参数带入　　　　　　　　
                    String url = weixinOAuthService.getOAuth2CodeBySnsapiBase(Configuration.getOAuthAppId(), Configuration.getProperty("weixin4j.oauth.url"));
                    response.sendRedirect(url);
                    return false;
                }
            }
        }
        return true;
    }


    /**
     * 微信授权第二步：
     * 1、用户同意授权，获取code
     * 2、通过code换取网页授权access_token
     *
     * @param code
     * @return
     * @throws IOException
     */
    @ApiOperation(value = "网页授权", notes = "网页授权")
    @GetMapping("/getOAuthVO")
    public SnsAccessToken getOAuthVO(@RequestParam(value = "code", required = true) String code, HttpServletResponse response) throws IOException {
        logger.info("网页授权--------------------");
        logger.info("==================code：{}" + code);

        if (code == null || code.equals("")) {
            //TODO 1 通过用户授权，获取code
            String returnUrl = org.apache.commons.lang3.StringUtils.join(Configuration.getProperty("weixin4j.getOAuthVO.url"));
            logger.info("==================授权地址：{}" + returnUrl);
            //将参数带入　　　　
            String url = weixinOAuthService.getOAuth2CodeBySnsapiBase(Configuration.getOAuthAppId(), returnUrl);
            logger.info("url:{}", url);
            response.sendRedirect(url);
            return null;
        } else {
            //TODO 2、通过code获取到token信息，然后做相对应的业务处理
            //查询用户的openid,因为code只能使用一次，所以将openid保存在页面中
            try {
                SnsAccessToken snsAccessToken = weixinOAuthService.getOauthToken(Configuration.getOAuthAppId(), Configuration.getOAuthSecret(), code);
                logger.info("authTokenVO--------------------authTokenVO:{}", snsAccessToken.toString());
                logger.info("授权之后的openid===============2========openid:{}", snsAccessToken.getOpenid());

                return snsAccessToken;
            } catch (WeixinException ex) {
                ex.printStackTrace();
                //数据异常继续请求å
                logger.info("WeixinException异常处理{}", ex.getStackTrace());
//                    OAuth2 oauth2 = new OAuth2();
                //将参数带入　　　　　　　　
                String url = weixinOAuthService.getOAuth2CodeBySnsapiBase(Configuration.getOAuthAppId(), Configuration.getProperty("weixin4j.oauth.url"));
                response.sendRedirect(url);
            }
        }
        return null;
    }

    @ApiOperation(value = "获取JSSDK参数WxConfig", notes = "获取JSSDK参数WxConfig")
    @GetMapping("/getWxConfig")
    public JsonResult getWxConfig(@ApiParam(value = "需要授权的请求地址", required = false) @RequestParam(value = "url", required = false) String url) throws Exception {
        JsonResult result = new JsonResult();
        try{
            WeixinBuilder b = WeixinBuilder.newInstance();
            b.setTicketLoader(wxTicketLoader);
            b.setTokenLoader(wxTokenLoader);
            Weixin weixin = b.build();
            JsSdkComponent jsSdkComponent = weixin.js();
            WxConfig wxConfig = jsSdkComponent.getWxConfig(url);
            if(wxConfig != null){
                result.setCode(JSONResult.SUCCESS);
                result.setData(wxConfig);
            }else{
                result.setCode(JSONResult.FAIL);
                result.setMessage("请求参数异常，请检查！");
            }
        }catch (Exception e){
            e.printStackTrace();
            result.setCode(JSONResult.FAIL);
            result.setMessage(e.getMessage());
        }
        return result;
    }

    @ApiOperation(value = "根据code获取用户信息", notes = "根据code获取用户信息")
    @GetMapping("/getSnsUserByCode")
    public JsonResult getSnsUserByCode(@ApiParam(value = "code", required = true) @RequestParam(value = "code", required = true) String code) throws Exception {
        JsonResult result = new JsonResult();
        try{
            WeixinBuilder b = WeixinBuilder.newInstance();
            b.setTicketLoader(wxTicketLoader);
            b.setTokenLoader(wxTokenLoader);
            Weixin weixin = b.build();
            SnsComponent snsComponent = weixin.sns();
            SnsUser snsUser = snsComponent.getSnsUserByCode(code);
            if(snsUser != null){
                result.setCode(JSONResult.SUCCESS);
                result.setData(snsUser);
            }else{
                result.setCode(JSONResult.FAIL);
                result.setMessage("请求参数异常，请检查！");
            }
        }catch (Exception e){
            e.printStackTrace();
            result.setCode(JSONResult.FAIL);
            result.setMessage(e.getMessage());
        }
        return result;
    }

    //创建菜单
    @ApiOperation(value = "创建菜单", notes = "创建菜单")
    @PostMapping(value = "createMenuByJson")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", dataType = "String", name = "json", value = "菜单json字符串", required = true),
            @ApiImplicitParam(paramType = "query", dataType = "String", name = "menuPass", value = "接口秘钥", required = true)
    })
    public JsonResult createMenuByJson(@RequestParam String json, @RequestParam String menuPass) {
        JsonResult result = new JsonResult();
        //检查请求有效性
        JSONObject jsonObject = null;
        try{
            jsonObject = JSON.parseObject(json);
        }catch (Exception e){
            e.printStackTrace();
            logger.info("json解析异常 ： " + json);
            result.setCode(JSONResult.FAIL);
            result.setMessage("json解析异常，请检查");
            return result;
        }

        if(menuPass == null){
            result.setCode(JSONResult.FAIL);
            result.setMessage("menuPass不能为空");
            return result;
        }
        Object object = redisUtil.get("menuPass");
        if(object == null){
            result.setCode(JSONResult.FAIL);
            result.setMessage("接口秘钥配置为空，请联系管理员");
            return result;
        }
        if(!object.toString().equalsIgnoreCase(menuPass)){
            result.setCode(JSONResult.FAIL);
            result.setMessage("接口秘钥错误！");
            return result;
        }
        try {

            //创建通讯组件
            WeixinBuilder b = WeixinBuilder.newInstance();
            Weixin weixin = b.build();

            logger.info("menu:" + json);

            create(weixin, jsonObject);
        } catch (WeixinException e) {
            e.printStackTrace();
            result.setCode(JSONResult.FAIL);
            result.setMessage("菜单创建失败：" + e.getMessage());
            return result;
        }
        result.setCode(JSONResult.SUCCESS);
        return result;
    }


    //创建菜单
    @ApiOperation(value = "创建菜单", notes = "创建菜单")
    @GetMapping(value = "createMenu")
    public JsonResult createMenu() {
        JsonResult result = new JsonResult();
        try {

            //创建通讯组件
            WeixinBuilder b = WeixinBuilder.newInstance();
            Weixin weixin = b.build();

            //创建菜单对象
            JSONObject jsonObject = new JSONObject();
            //创建按钮列表
            List<JSONObject> jsonObjectList = new ArrayList<>();
            //内部测试
            JSONObject jsonObject0 = new JSONObject();
            jsonObject0.put("name", "内部测试");
            jsonObject0.put("type", "view");
            jsonObject0.put("url", "https://wx.dev.yxytcar.cn/redEnvelopes");
            jsonObjectList.add(jsonObject0);
            //新增新闻资讯跳转按钮
            JSONObject jsonObject1 = new JSONObject();
            jsonObject1.put("name", "新闻资讯");
            jsonObject1.put("type", "view");
            jsonObject1.put("url", "https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzU3MzU5NjgxOA==#wechat_redirect");
            //新增小程序跳转按钮
            JSONObject jsonObject2 = new JSONObject();
            jsonObject2.put("type", "miniprogram");
            jsonObject2.put("name", "办理ETC");
            jsonObject2.put("url", "http://mp.weixin.qq.com");
            jsonObject2.put("appid", "wxa342510eab64e9cc");
            jsonObject2.put("pagepath", "pages/index/index");
            jsonObjectList.add(jsonObject1);
            jsonObjectList.add(jsonObject2);
            //菜单和按钮绑定
            jsonObject.put("button", jsonObjectList);
            logger.info("menu:" + JSON.toJSONString(jsonObject));

            create(weixin, jsonObject);
        } catch (WeixinException e) {
            e.printStackTrace();
            result.setCode(JSONResult.FAIL);
            result.setMessage("菜单创建失败：" + e.getMessage());
            return result;
        }
        result.setCode(JSONResult.SUCCESS);
        return result;
    }

    /**
     * 请求方法
     *
     * @param weixin
     * @param menu
     * @throws WeixinException
     */
    public void create(Weixin weixin, JSONObject menu) throws WeixinException {
        if (menu != null) {
            HttpsClient http = new HttpsClient();
            Response res = http.post("https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + weixin.getToken().getAccess_token(), menu);
            JSONObject jsonObj = res.asJSONObject();
            if (jsonObj != null) {
                if (Configuration.isDebug()) {
                    logger.info("/menu/create返回json：" + jsonObj.toString());
                }

                Object errcode = jsonObj.get("errcode");
                if (errcode != null && !errcode.toString().equals("0")) {
                    WeixinSupport weixinSupport = new WeixinSupport();
                    throw new WeixinException(weixinSupport.getCause(jsonObj.getIntValue("errcode")));
                }
            }

        } else {
            throw new IllegalArgumentException("menu can't be null or menu.button can't be null");
        }
    }


}

